package com.unisoc.keyguard;

import com.android.systemui.R;
import com.android.systemui.Dependency;
import com.android.keyguard.EmergencyCarrierArea;
import com.android.keyguard.KeyguardPinBasedInputView;
import com.android.keyguard.KeyguardEsimArea;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.internal.telephony.PhoneConstants;

import com.unisoc.keyguard.util.SimLockUtil;
import com.unisoc.sdk.common.telephony.UniTelephonyManager;
import com.android.unisoc.telephony.RadioInteractor;

import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;

/**
 * Displays a SimLock PIN pad for unlocking.
 */
public class KeyguardSimLockView extends KeyguardPinBasedInputView {
    private static final String TAG = "KeyguardSimLockView";
    private static final boolean DEBUG = true;
    private static final int PASSWORD_LENGTH_MIN = 8;
    private static final int PASSWORD_LENGTH_MAX = 16;
    private static final int EVENT_SET_FACILITY_LOCK_REQUEST = 1;
    private static final int EVENT_SET_FACILITY_LOCK_RESULT = 100;
    private static final int PHONE_ID_DEFAULT = 0;
    private static final int SERVICE_CLASS_MAX = 7; // Max SERVICE_CLASS value

    private RadioInteractor mRadioInteractor = null;
    private boolean mShouldResetState = true;
    private int mState = UniTelephonyManager.SIM_STATE_NETWORK_LOCKED;
    private int mUnlockType = UniTelephonyManager.UNLOCK_NETWORK;
    private String mFacility = UniTelephonyManager.CB_FACILITY_BA_PN;

    private ProgressDialog mSimUnlockProgressDialog = null;

    // Below flag is set to true during power-up or when a new SIM card inserted on device.
    // When this is true and when SIM card is SIMLOCK locked state, on SIMLOCK lock screen, message would
    // be displayed to inform user about the number of remaining SIMLOCK attempts left.
    private int mRemainingAttempts = -1;
    private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
    private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
    private TextView mSimlockTitleView;
    private TextView mDismissButton;

    KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
        @Override
        public void onSimStateChanged(int subId, int slotId, int simState) {
            if (DEBUG) Log.d(TAG, "onSimStateChanged(subId=" + subId + ", slotId=" + slotId + ", state=" + simState + ")");
            if(SimLockUtil.isByNv()){
                if (DEBUG) Log.d(TAG, "onSimStateChanged(Simlock unlock by nv turned on!)");
                return;
            }
            switch(simState) {
            // If the SIM is removed, then we must remove the keyguard. It will be put up
            // again when the PUK locked SIM is re-entered.
            case TelephonyManager.SIM_STATE_ABSENT:
                handleSimAbsent(slotId);
                break;
            case UniTelephonyManager.SIM_STATE_SIM_LOCKED_PERMANENTLY:
                // onSimStateChanged callback can fire when the SIMLOCK is not currently
                // active and mCallback is null.
                handlePermanentLock(simState);
                break;
            case TelephonyManager.SIM_STATE_READY:
                handleSimReady(slotId);
                break;
            default:
                handleOtherState(simState);
                break;
            }
        }

        @Override
        public void onUpdateSimLockDismissBtn(boolean dismissProhibited) {
            Log.d(TAG, "onUpdateSimLockDismissBtn: " + dismissProhibited);
            KeyguardSimLockMonitor.mBroadcastReceived = false;
            if (mContext.getResources().getBoolean(com.android.internal.R.bool.simlock_view_dismiss_conditionally)
                    && mDismissButton != null) {
                mDismissButton.setVisibility(!dismissProhibited? View.VISIBLE : View.GONE);
            }
        }
    };

    public KeyguardSimLockView(Context context) {
        this(context, null);
    }

    public KeyguardSimLockView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mRadioInteractor = new RadioInteractor(context);
    }

    private void handleSimAbsent(int slotId) {
        TelephonyManager teleMgr = (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
        if (mSlotId == slotId && teleMgr != null
                && teleMgr.getSimState(mSlotId) == TelephonyManager.SIM_STATE_ABSENT) {
            dismissWithAuthentication();
        }
    }

    private void handlePermanentLock(int simState) {
        mState = simState;
        resetState();
        dismissWithAuthentication();
    }

    private void handleSimReady(int slotId) {
        if (mSlotId == slotId) {
            mRemainingAttempts = -1;
            resetState();
            dismissWithAuthentication();
        }
    }

    private void handleOtherState(int simState) {
        if (SimLockUtil.isSimLockState(simState)) {
            if (mState != simState) {
                mRemainingAttempts = -1;
            }
            mState = simState;
            mUnlockType = SimLockUtil.getUnlockTypeByState(mState);
            mFacility = SimLockUtil.getFacility(mUnlockType);
            if (DEBUG) Log.d(TAG, "State is SimLock: mState= " + mState + ", mUnlockType= " + mUnlockType);
        }
        resetState();
    }

    private void dismissWithAuthentication() {
        if (mCallback != null) {
            mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
        }
    }

    @Override
    public void resetState() {
        super.resetState();
        if (DEBUG) Log.d(TAG, "Resetting state");
        handleSubInfoChangeIfNeeded();

        if (mShouldResetState) {
            showSecurityMessage();
        }

        boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);

        KeyguardEsimArea esimButton = findViewById(R.id.keyguard_esim_area);
        esimButton.setVisibility(isEsimLocked ? View.VISIBLE : View.GONE);
    }

    private void showSecurityMessage() {
        updateTitle(mState);
        if (mSecurityMessageDisplay != null) {
            if (mRemainingAttempts >= 0) {
                mSecurityMessageDisplay.setMessage(getSimlockPwErrorMessage(
                        mRemainingAttempts, true));
                return;
            }
            mRemainingAttempts = mRadioInteractor.getSimLockRemainTimes(mUnlockType, 0);
            mSecurityMessageDisplay.setMessage(getSimlockPwErrorMessage(
                    mRemainingAttempts, true));
        }
    }

    private void updateTitle(int state) {
        Log.d(TAG, "updateTitle: state = " + state);
        mSimlockTitleView.setText(SimLockUtil.getTitleByState(state));
    }

    private void handleSubInfoChangeIfNeeded() {
        SubscriptionManager subManager = (SubscriptionManager)
                mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
        KeyguardUpdateMonitor monitor =  Dependency.get(KeyguardUpdateMonitor.class);
        int slotId = monitor.getNextSlotIdForSimLockState(mState);
        Log.d(TAG, "handleSubInfoChangeIfNeeded: mState = " + mState + ", slotId = " + slotId);
        if (slotId != mSlotId && SubscriptionManager.isValidSlotIndex(slotId)) {
            mSlotId = slotId;
            int[] subIds = subManager.getSubscriptionIds(mSlotId);
            if (subIds != null && subIds.length > 0) {
                mSubId = subIds[0];
            }
            mRemainingAttempts = -1;
        }
    }

    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        resetState();
    }

    @Override
    protected int getPromptReasonStringRes(int reason) {
        return 0;
    }

    private String getSimlockPwErrorMessage(int attemptsRemaining, boolean isDefault) {
        String displayMessage;
        int msgId;
        if (attemptsRemaining == 0) {
            displayMessage = getContext().getString(R.string.kg_password_wrong_simlock_code_pukked);
        } else if (attemptsRemaining > 0) {
            msgId = isDefault ? R.plurals.kg_password_default_simlock_message :
                R.plurals.kg_password_wrong_simlock_code;
            displayMessage = getContext().getResources()
                    .getQuantityString(msgId, attemptsRemaining, attemptsRemaining);
        } else {
            msgId = isDefault ? R.string.kg_simlock_instructions : R.string.kg_password_simlock_failed;
            displayMessage = getContext().getString(msgId);
        }
        if (KeyguardEsimArea.isEsimLocked(mContext, mSubId)) {
            displayMessage = getResources()
                    .getString(R.string.kg_sim_lock_esim_instructions, displayMessage);
        }
        if (DEBUG) Log.d(TAG, "getSimlockPwErrorMessage:"
                + " attemptsRemaining=" + attemptsRemaining + " displayMessage=" + displayMessage);
        return displayMessage;
    }

    @Override
    protected boolean shouldLockout(long deadline) {
        return false;
    }

    @Override
    protected int getPasswordTextViewId() {
        return R.id.simLockEntry;
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        if (mEcaView instanceof EmergencyCarrierArea) {
            Log.v(TAG, "onFinishInflate: is an EmergencyCarrierArea");
            ((EmergencyCarrierArea) mEcaView).setCarrierTextVisible(true);
        }
        mSimlockTitleView = findViewById(R.id.keyguard_simlock_title);
        mDismissButton = findViewById(R.id.kg_simlock_dismiss_button);
        mDismissButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d(TAG, "dismiss SimLock view");
                doHapticKeyClick();
                KeyguardSimLockMonitor.getInstance(mContext).setSimLockCanceled(true);
                KeyguardSimLockMonitor.getInstance(mContext).reportSimLockCanceled(mSubId);
                mCallback.dismissSimLock(KeyguardUpdateMonitor.getCurrentUser());
            }
        });
        if (mContext.getResources().getBoolean(com.android.internal.R.bool.simlock_view_dismiss_conditionally)) {
            mDismissButton.setVisibility(View.GONE);
        }
        if (KeyguardSimLockMonitor.mBroadcastReceived) {
            mUpdateMonitorCallback.onUpdateSimLockDismissBtn(KeyguardSimLockMonitor.getInstance(mContext).hideBtn());
            KeyguardSimLockMonitor.mBroadcastReceived = false;
        }
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        Dependency.get(KeyguardUpdateMonitor.class).registerCallback(mUpdateMonitorCallback); //UNISOC: Modify for bug 1331669
        Log.d(TAG, "onAttachedToWindow");
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        Dependency.get(KeyguardUpdateMonitor.class).removeCallback(mUpdateMonitorCallback); //UNISOC: Modify for bug 1331669
        Log.d(TAG, "onDetachedFromWindow");
    }

    @Override
    public void showUsabilityHint() {
    }

    @Override
    public void onResume(int reason) {
        mShouldResetState = true;
        super.onResume(reason);
        Log.d(TAG, "onResume");
        if(SimLockUtil.isByNv()){
            mState = KeyguardSimLockMonitor.getInstance(mContext).getNvState();
            mUnlockType = SimLockUtil.getUnlockTypeByState(mState);
            mFacility = SimLockUtil.getFacility(mUnlockType);
            resetState();
        } else {
            resetState();
        }
    }

    @Override
    public void onPause() {
        mShouldResetState = false;
        super.onPause();
        Log.v(TAG, "onPause");
        // dismiss the dialog.
        if (mSimUnlockProgressDialog != null) {
            mSimUnlockProgressDialog.dismiss();
            mSimUnlockProgressDialog = null;
        }
    }

    private void setFacilityLock(String facility, boolean lockState, String password,
            int serviceClass, int phoneId) {
        HandlerThread thread = new HandlerThread(TAG);
        thread.start();
        Messenger messenger = new Messenger(new Handler(thread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                Log.d(TAG, "Messenger handleMessage: " + msg);
                switch (msg.what) {
                case EVENT_SET_FACILITY_LOCK_REQUEST:
                    int result = msg.arg1;
                    int remainTimes = msg.arg2;
                    mSimLockHandler.sendMessage(mSimLockHandler.obtainMessage(
                            EVENT_SET_FACILITY_LOCK_RESULT, result, remainTimes, null));
                    break;
                default:
                    break;
                }
            }
        });
        mRadioInteractor.setFacilityLock(facility, lockState, password, serviceClass, null,
                messenger, EVENT_SET_FACILITY_LOCK_REQUEST, phoneId);
    }

    private Handler mSimLockHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case EVENT_SET_FACILITY_LOCK_RESULT:
                int result = msg.arg1;
                mRemainingAttempts = msg.arg2;
                Log.d(TAG, "EVENT_SET_FACILITY_LOCK_RESULT: [" + result + "," + mRemainingAttempts + "]");
                if (mSimUnlockProgressDialog != null) {
                    mSimUnlockProgressDialog.hide();
                }
                resetPasswordText(true /* animate */,
                        result != PhoneConstants.PIN_RESULT_SUCCESS /* announce */);
                if (result == PhoneConstants.PIN_RESULT_SUCCESS) {
                    if (SimLockUtil.isByNv()) {
                        KeyguardSimLockMonitor.getInstance(mContext).reportUnlockedByNV();
                    } else {
                        KeyguardSimLockMonitor.getInstance(mContext).reportUnlockedBySIM();
                    }
                    KeyguardUpdateMonitor monitor =  Dependency.get(KeyguardUpdateMonitor.class);
                    mRemainingAttempts = -1;
                    dismissWithAuthentication();
                } else {
                    mSecurityMessageDisplay.setMessage(
                            getSimlockPwErrorMessage(mRemainingAttempts, false));
                }
                mCallback.userActivity();
                break;
            default:
                break;
            }
        }
    };

    private Dialog getSimUnlockProgressDialog() {
        if (mSimUnlockProgressDialog == null) {
            mSimUnlockProgressDialog = new ProgressDialog(mContext);
            mSimUnlockProgressDialog.setMessage(
                    mContext.getString(R.string.kg_sim_unlock_progress_dialog_message));
            mSimUnlockProgressDialog.setIndeterminate(true);
            mSimUnlockProgressDialog.setCancelable(false);
            mSimUnlockProgressDialog.getWindow().setType(
                    WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
        }
        return mSimUnlockProgressDialog;
    }

    @Override
    protected void verifyPasswordAndUnlock() {
        String entry = mPasswordEntry.getText();
        Log.d(TAG, "verifyPasswordAndUnlock: " + entry);
        if (entry.length() < PASSWORD_LENGTH_MIN || entry.length() > PASSWORD_LENGTH_MAX) {
            // otherwise, display a message to the user, and don't submit.
            mSecurityMessageDisplay.setMessage(R.string.kg_invalid_simlock_pin_hint);
            resetPasswordText(true /* animate */, true /* announce */);
            mCallback.userActivity();
            return;
        }

        getSimUnlockProgressDialog().show();

        setFacilityLock(mFacility, false, entry, SERVICE_CLASS_MAX, PHONE_ID_DEFAULT);
    }

    @Override
    public void startAppearAnimation() {
    }

    @Override
    public boolean startDisappearAnimation(Runnable finishRunnable) {
        return false;
    }

    @Override
    public CharSequence getTitle() {
        return getContext().getString(R.string.keyguard_accessibility_sim_lock_unlock);
    }
}

